package com.lyc.api;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.lyc.constants.Constants;
import com.lyc.utils.HttpClient;
import com.lyc.utils.RandomNumber;
import org.apache.commons.codec.digest.DigestUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.*;

/**
 * 穿山甲广告客户端API。
 */
public class CsjApiClient {

    private static final Gson policyGson = new Gson();
    private static final String HOST = "https://open-api.csjplatform.com";

    public static int CSJ_APP_ID;
    public static int CSJ_ROLE_ID;
    public static int CSJ_USER_ID;
    public static String CSJ_SECURITY_KEY;

    static {
        loadProperties();
    }

    private static void loadProperties() {
        Properties props = new Properties();
        try (FileInputStream fis = new FileInputStream(new File(Constants.ACCOUNT_PATH + "account.properties"))) {
            props.load(fis);

            CSJ_APP_ID = Integer.parseInt(props.getProperty("CSJ_APP_ID"));
            CSJ_ROLE_ID = Integer.parseInt(props.getProperty("CSJ_ROLE_ID"));
            CSJ_USER_ID = Integer.parseInt(props.getProperty("CSJ_USER_ID"));
            CSJ_SECURITY_KEY = String.valueOf(props.getProperty("CSJ_SECURITY_KEY"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建穿山甲半屏插屏广告。
     *
     * @return 成功时返回广告位 ID；失败时返回 -1
     */
    public static Integer createCsjHalfScreenInsertAd() {
        Map<String, Object> specificParams = new HashMap<>();
        specificParams.put("ad_rollout_size", 2);
        specificParams.put("render_type", 1);
        specificParams.put("accept_material_type", 3);
        specificParams.put("orientation", 1);
        specificParams.put("skip_duration", 5);
        specificParams.put("video_voice_control", 1);
        specificParams.put("video_auto_play", 1);

        return createCsjAd(9, 1, specificParams);
    }

    public static String queryCsjAdNameById(Integer adSlotId) {
        long timestamp = System.currentTimeMillis() / 1000;
        int nonce = RandomNumber.generateRandom8DigitNumber();

        Map<String, Object> params = new HashMap<>();
        params.put("user_id", CSJ_USER_ID);
        params.put("role_id", CSJ_ROLE_ID);
        params.put("sign", generateSign(timestamp + "", nonce));
        params.put("timestamp", timestamp);
        params.put("nonce", nonce);
        params.put("version", "1.0");

        params.put("page", 1);
        params.put("page_size", 1);
        params.put("ad_slot_id", adSlotId);
        params.put("app_id", CSJ_APP_ID);

        Map<String, String> headers = getHeaders();
        String response = HttpClient.doPost(HOST + "/union/media/open_api/code/query", params, headers);

        System.out.println("response = " + response);

        Type responseType = new TypeToken<Map<String, Object>>() {}.getType();
        Map<String, Object> responseMap = policyGson.fromJson(response, responseType);

        int code = ((Number) responseMap.get("code")).intValue();
        String message = (String) responseMap.get("message");

        if (code == 0 && "success".equalsIgnoreCase(message)) {
            Map<String, Object> dataMap = (Map<String, Object>) responseMap.get("data");
            List<Map<String, Object>> adSlotList = (List<Map<String, Object>>) dataMap.get("ad_slot_list");

            if (adSlotList != null && !adSlotList.isEmpty()) {
                Map<String, Object> adSlot = adSlotList.get(0);
                String adSlotName = (String) adSlot.get("ad_slot_name");
                // System.out.println("adSlotName = " + adSlotName);
                return adSlotName;
            } else {
                System.out.println("adSlotList is empty or null.");
            }
        } else {
            System.out.println("查询代码位失败。 Code: " + code);
        }
        return null;
    }

    /**
     * 创建穿山甲优选插屏广告。
     *
     * @return 成功时返回广告位 ID；失败时返回 -1
     */
    public static Integer createCsjPreferredInsertAd() {
        Map<String, Object> specificParams = new HashMap<>();
        specificParams.put("ad_rollout_size", 3);
        specificParams.put("render_type", 1);
        specificParams.put("accept_material_type", 3);
        specificParams.put("orientation", 1);
        specificParams.put("skip_duration", 5);
        specificParams.put("video_voice_control", 1);
        specificParams.put("video_auto_play", 1);

        return createCsjAd(9, 1, specificParams);
    }

    /**
     * 创建穿山甲优选插屏兜底广告。
     *
     * @return 成功时返回广告位 ID；失败时返回 -1
     */
    public static Integer createCsjDouDiHalfScreenInsertAd() {
        Map<String, Object> specificParams = new HashMap<>();
        specificParams.put("ad_rollout_size", 3);
        specificParams.put("render_type", 1);
        specificParams.put("accept_material_type", 3);
        specificParams.put("orientation", 1);
        specificParams.put("skip_duration", 5);
        specificParams.put("video_voice_control", 1);
        specificParams.put("video_auto_play", 1);

        return createCsjAd(9, 0, specificParams);
    }

    /**
     * 创建穿山甲激励兜底视频广告。
     *
     * @return 成功时返回广告位 ID；失败时返回 -1
     */
    public static Integer createCsjDouDiRewardAd() {
        Map<String, Object> specificParams = new HashMap<>();
        specificParams.put("render_type", 1);
        specificParams.put("orientation", 1);
        specificParams.put("reward_is_callback", 1);
        specificParams.put("reward_callback_url", "http://quanminchangwan.kuhuanqiye.top/api/huitiao.houtai/chuanshanjia");

        return createCsjAd(5, 0, specificParams);
    }

    /**
     * 创建穿山甲激励视频广告。
     *
     * @return 成功时返回广告位 ID；失败时返回 -1
     */
    public static Integer createCsjRewardAd() {
        Map<String, Object> specificParams = new HashMap<>();
        specificParams.put("render_type", 1);
        specificParams.put("orientation", 1);
        specificParams.put("reward_is_callback", 1);
        specificParams.put("reward_callback_url", "http://quanminchangwan.kuhuanqiye.top/api/huitiao.houtai/chuanshanjia");

        return createCsjAd(5, 1, specificParams);
    }

    /**
     * 创建穿山甲开屏广告。
     *
     * @return 成功时返回广告位 ID；失败时返回 -1
     */
    public static Integer createCsjSplashAd() {
        Map<String, Object> specificParams = new HashMap<>();
        specificParams.put("render_type", 3);
        specificParams.put("orientation", 1);
        specificParams.put("splash_shake", 1);

        return createCsjAd(3, 1, specificParams);
    }

    /**
     * 创建穿山甲开屏兜底广告。
     *
     * @return 成功时返回广告位 ID；失败时返回 -1
     */
    public static Integer createCsjDouDiSplashAd() {
        Map<String, Object> specificParams = new HashMap<>();
        specificParams.put("render_type", 3);
        specificParams.put("orientation", 1);
        specificParams.put("splash_shake", 1);

        return createCsjAd(3, 0, specificParams);
    }

    /**
     * 创建穿山甲Banner广告。
     *
     * @return 成功时返回广告位 ID；失败时返回 -1
     */
    public static Integer createCsjBannerAd() {
        Map<String, Object> specificParams = new HashMap<>();
        specificParams.put("render_type", 1);
        specificParams.put("slide_banner", 2);
        specificParams.put("width", 600);
        specificParams.put("height", 300);

        return createCsjAd(2, 1, specificParams);
    }

    /**
     * 创建穿山甲Banner兜底广告。
     *
     * @return 成功时返回广告位 ID；失败时返回 -1
     */
    public static Integer createCsjDouDiBannerAd() {
        Map<String, Object> specificParams = new HashMap<>();
        specificParams.put("render_type", 1);
        specificParams.put("slide_banner", 2);
        specificParams.put("width", 600);
        specificParams.put("height", 300);

        return createCsjAd(2, 0, specificParams);
    }

    /**
     * 创建穿山甲原生广告。
     *
     * @return 成功时返回广告位 ID；失败时返回 -1
     */
    public static Integer createCsjNativeAd() {
        Map<String, Object> specificParams = new HashMap<>();
        specificParams.put("render_type", 1);
        specificParams.put("accept_material_type", 3);
        specificParams.put("template_layouts", new int[]{1, 2, 3, 4, 5, 6, 7});
        specificParams.put("video_voice_control", 1);

        return createCsjAd(1, 1, specificParams);
    }

    /**
     * 创建穿山甲原生兜底广告。
     *
     * @return 成功时返回广告位 ID；失败时返回 -1
     */
    public static Integer createCsjDouDiNativeAd() {
        Map<String, Object> specificParams = new HashMap<>();
        specificParams.put("render_type", 1);
        specificParams.put("accept_material_type", 3);
        specificParams.put("template_layouts", new int[]{1, 2, 3, 4, 5, 6, 7});
        specificParams.put("video_voice_control", 1);

        return createCsjAd(1, 0, specificParams);
    }

    /**
     * 创建穿山甲广告位。
     *
     * @param adSlotType 广告位类型
     * @param biddingType 竞价类型
     * @param specificParams 特定的请求参数
     * @return 成功时返回广告位 ID；失败时返回 -1
     */
    private static Integer createCsjAd(int adSlotType, int biddingType, Map<String, Object> specificParams) {
        long timestamp = System.currentTimeMillis() / 1000;
        int nonce = RandomNumber.generateRandom8DigitNumber();

        Map<String, Object> params = new HashMap<>();
        params.put("user_id", CSJ_USER_ID);
        params.put("role_id", CSJ_ROLE_ID);
        params.put("sign", generateSign(timestamp + "", nonce));
        params.put("timestamp", timestamp);
        params.put("nonce", nonce);
        params.put("version", "1.0");
        params.put("app_id", CSJ_APP_ID);
        params.put("ad_slot_type", adSlotType);
        params.put("bidding_type", biddingType);
        params.put("use_mediation", "1");
        params.putAll(specificParams);

        Map<String, String> headers = getHeaders();
        String response = HttpClient.doPost(HOST + "/union/media/open_api/code/create", params, headers);

        return parseResponse(response);
    }

    /**
     * 解析服务器返回的 JSON 响应字符串。
     *
     * @param response 服务器返回的 JSON 字符串响应
     * @return 成功时返回广告位 ID；失败时返回 -1
     */
    private static Integer parseResponse(String response) {
        Type responseType = new TypeToken<Map<String, Object>>() {}.getType();
        Map<String, Object> responseMap = policyGson.fromJson(response, responseType);

        int code = ((Number) responseMap.get("code")).intValue();
        String message = (String) responseMap.get("message");

        if (code == 0 && "success".equalsIgnoreCase(message)) {
            Map<String, Object> adSlotMap = (Map<String, Object>) responseMap.get("data");
            return ((Number) adSlotMap.get("ad_slot_id")).intValue();
        } else {
            System.out.println("创建代码位失败。 Code: " + code);
            return -1;
        }
    }

    /**
     * 设置请求头。
     *
     * @return 请求头
     */
    private static Map<String, String> getHeaders() {
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        headers.put("Accept", "application/json");
        return headers;
    }

    /**
     * 生成签名。
     *
     * @param timestamp 时间戳
     * @param nonce 随机数
     * @return 签名
     */
    private static String generateSign(String timestamp, int nonce) {
        List<String> strings = Arrays.asList(
                CSJ_SECURITY_KEY,
                timestamp,
                Integer.toString(nonce)
        );
        Collections.sort(strings);

        StringBuilder sb = new StringBuilder();
        for (String s : strings) {
            sb.append(s);
        }

        return DigestUtils.sha1Hex(sb.toString());
    }
}
